package com.joysuch.wwyt.bp.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.joysuch.wwyt.bp.bean.change.*;
import com.joysuch.wwyt.bp.entity.*;
import com.joysuch.wwyt.bp.entity.change.BpChangeRecord;
import com.joysuch.wwyt.bp.enums.ChangeRecordStates;
import com.joysuch.wwyt.bp.enums.ChangeRecordType;
import com.joysuch.wwyt.bp.repository.*;
import com.joysuch.wwyt.bp.service.BpChangeRecordService;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.mh.entity.MhMajorHazard;
import com.joysuch.wwyt.mh.entity.MhMonitoringPoint;
import com.joysuch.wwyt.mh.entity.MhMonitoringType;
import com.joysuch.wwyt.mh.repository.MhMajorHazardDao;
import com.joysuch.wwyt.mh.repository.MhMonitoringPointDao;
import com.joysuch.wwyt.mh.repository.MhMonitoringTypeDao;
import com.joysuch.wwyt.mh.service.MhMonitoringPointService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.text.ParseException;
import java.util.*;

@Service
@Slf4j
public class BpChangeRecordServiceImpl implements BpChangeRecordService {

@Autowired
private BpChangeRecordDao bpChangeRecordDao;

@Autowired
private BaseUserDao baseUserDao;

@Autowired
private BpDepartDao bpDepartDao;

@Autowired
private BpJobDao bpJobDao;

@Autowired
private BpProductionFacilityDao bpProductionFacilityDao;

@Autowired
private BpStorageTankDao bpStorageTankDao;

@Autowired
private BpStorageTankAreaDao bpStorageTankAreaDao;

@Autowired
private BpManufacturingTechDao bpManufacturingTechDao;

@Autowired
private MhMajorHazardDao mhMajorHazardDao;

@Autowired
private BpCertificateDao bpCertificateDao;

@Autowired
private MhMonitoringPointDao mhMonitoringPointDao;

@Autowired
private MhMonitoringPointService mhMonitoringPointService;

@Autowired
private MhMonitoringTypeDao mhMonitoringTypeDao;




@Override
public Page<BpChangeRecordListBean> pageList(BpChangeRecordQueryBean queryBean, Pageable pageable) {
        Specification<BpChangeRecord> specification = new Specification<BpChangeRecord>() {
@Override
public Predicate toPredicate(Root<BpChangeRecord> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder cb) {
        List<Predicate> predicates = new ArrayList<>();
        if (StringUtils.isNotEmpty(queryBean.getChangeItem())) {
        predicates.add( cb.like(root.get("changeItem"), "%"+queryBean.getChangeItem()+"%"));
        }
        if(StringUtils.isNotEmpty(queryBean.getChangeType())){
        predicates.add(cb.equal(root.get("changeType"), queryBean.getChangeType()));
        }

        if(queryBean.getApplyDateStart() != null && queryBean.getApplyDateEnd() != null){
        predicates.add(cb.between(root.get("applyDate"), queryBean.getApplyDateStart(), queryBean.getApplyDateEnd()));
        }
        if(queryBean.getState() != null){
        predicates.add(cb.equal(root.get("state"), queryBean.getState()));
        }
        if(queryBean.getApproveDateStart() != null && queryBean.getApproveDateEnd() != null){
        predicates.add(cb.between(root.get("approveDate"), queryBean.getApproveDateStart(), queryBean.getApproveDateEnd()));
        }

        return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        }
        };
        Page<BpChangeRecord> page = bpChangeRecordDao.findAll(specification, pageable);
        List<BpChangeRecordListBean> beanList = new ArrayList<>();
        page.toList().stream().forEach(item-> beanList.add(convertBean(item)));

        return  new PageImpl<>(beanList,pageable, page.getTotalElements());
        }

@Override
public BpChangeRecord create(BpChangeRecordCreateBean bean) {
        BpChangeRecord changeRecord = new BpChangeRecord();
        BeanUtils.copyProperties(bean, changeRecord);
        // 状态为待审核
        changeRecord.setState(ChangeRecordStates.WAITING_FOR_AUDIT.getId());

        return bpChangeRecordDao.save(changeRecord);
        }

@Override
public void delete(Long id) {
        bpChangeRecordDao.deleteById(id);
        }

@Override
public BpChangeRecordListBean findById(Long id) {
        Optional<BpChangeRecord> entity = bpChangeRecordDao.findById(id);
        if(!entity.isPresent()){
        return null;
        }
        return convertBean(entity.get());
        }

/**
 * Bean 属性转换
 * @param entity
 * @return
 */
private BpChangeRecordListBean convertBean(BpChangeRecord entity){
        BpChangeRecordListBean bean  = new BpChangeRecordListBean();
        BeanUtils.copyProperties(entity,bean);
        //申请人姓名
        if(entity.getApplyUserId() != null){
        bean.setApplyUserName(baseUserDao.getRealNameById(entity.getApplyUserId()));

        }
        //申请人部门
        if(entity.getApplyDepartId() != null){
        bean.setApplyDepartName(bpDepartDao.findDepartNameById(entity.getApplyDepartId()));
        }
        //申请人岗位
        if(entity.getApplyJobId() != null){
        bean.setApplyJobName(bpJobDao.getNameById(entity.getApplyJobId()));
        }
        //状态描述
        if(entity.getState() != null){
        bean.setStateName(ChangeRecordStates.findNameById(entity.getState()));
        }
        //审批人
        if(entity.getApproveUserId() != null){
        bean.setApproveUserName(baseUserDao.getRealNameById(entity.getApproveUserId()));
        }
        //审批部门
        if(entity.getApproveDepartId() != null){
        bean.setApproveDepartName(bpDepartDao.findDepartNameById(entity.getApproveDepartId()));
        }
        if(entity.getChangeType()!= null){
        bean.setChangeTypeName(ChangeRecordType.findNameByCode(entity.getChangeType()));
        }

        return bean;
        }

@Override
@Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class)
public void approve(BpChangeRecordApproveBean bean) throws Exception {
        try {
        BpChangeRecord changeRecord =  bpChangeRecordDao.findById(bean.getId()).get();
        // 状态为审核结果： 通过/不通过
        changeRecord.setState(bean.getState());
        changeRecord.setApproveUserId(Context.getCurrentUserId());
        changeRecord.setApproveDate(new Date());

        changeRecord.setApproveDepartId(Context.getCurrentDepartId());
        bpChangeRecordDao.save(changeRecord);
        //审核不通过， 则不执行变更
        if(bean.getState() == ChangeRecordStates.AUDIT_FAILED.getId()){
        return;
        }

        //变更类型获取 变更子类型/变更类型
        String changeType = changeRecord.getChangeSubType() == null ? changeRecord.getChangeType(): changeRecord.getChangeSubType();
        Long changeId = changeRecord.getChangeItemSubId() == null ? changeRecord.getChangeItemId() : changeRecord.getChangeItemSubId();
        String changeOperation  = changeRecord.getChangeSubOperation() == null ? changeRecord.getChangeOperation(): changeRecord.getChangeSubOperation();

        //审核通过后执行变更操作
        if("删除".equals(changeOperation)){
        handleChange(changeId, changeType,null, changeOperation);
        return;
        }
        //修改操作
        if(changeRecord.getChangeDetails() != null){
        List<BpChangeRecordFieldBean> dataList = JSONArray.parseArray(changeRecord.getChangeDetails(),BpChangeRecordFieldBean.class);
        if(dataList.isEmpty()){
          return ;
        }
        //执行变更
        Map<String, Object> fieldMap = new HashMap<>();
        for(BpChangeRecordFieldBean r: dataList){
           fieldMap.put(r.getKey(), r.getNewValue());
        }
       // dataList.stream().collect(Collectors.toMap(BpChangeRecordFieldBean::getKey,BpChangeRecordFieldBean::getNewValue));
        handleChange(changeId, changeType, fieldMap, changeOperation);

        }
        } catch (Exception e) {
        log.error("变更管理：执行变更操作出错： "+e.getMessage() , e);
        throw new Exception(e);
        }

        }

/**
 * 判断是否存在待审批的或审批不通过的变更记录
 * @param id
 * @param changeType
 * @return
 */
@Override
public boolean checkPendingChange(Long id, String changeType) {

        BpChangeRecord changeRecord = bpChangeRecordDao.findFirstByChangeItemIdAndChangeTypeAndState(id, changeType,1);
        // 变更不存在
        if(changeRecord == null){
        return false;
        }
        return true;
        }

/**
 * 根据不同类型， 执行变更操作
 * @param id ： 每种类型数据主键ID
 * @param changeType 变更类型
 * @param fieldMap 变更字段Map列表
 */

private void handleChange(Long id, String changeType,  Map<String, Object> fieldMap, String changeOperation) throws IllegalAccessException {
        // 人员管理
        if(ChangeRecordType.USER.getCode().equalsIgnoreCase(changeType)){
        if("删除".equals(changeOperation)){
        Optional<BaseUser> baseUser = baseUserDao.findById(id);
        if(baseUser.isPresent()){
        baseUser.get().setDeleteFlag("1");
        baseUserDao.save(baseUser.get());
        }
        return;
        }
        changeUser(id, fieldMap);
        }else if(ChangeRecordType.USER_CERTIFICATE.getCode().equalsIgnoreCase(changeType)){
        //人员 资质证件
        if("删除".equals(changeOperation)){
        bpCertificateDao.deleteById(id);
        return;
        }
        changeUserCertificate(id, fieldMap);
        }else if(ChangeRecordType.DEVICE.getCode().equalsIgnoreCase(changeType)){
        //生产装置
        if("删除".equals(changeOperation)){
        bpProductionFacilityDao.deleteById(id);
        return;
        }
        changeDevice(id, fieldMap);
        }else if(ChangeRecordType.STORAGE_TANK.getCode().equalsIgnoreCase(changeType)){
        //储罐
        if("删除".equals(changeOperation)){
        bpStorageTankDao.deleteById(id);
        return;
        }
        changeStorageTank(id, fieldMap);
        }else if(ChangeRecordType.STORAGE_TANK_AREA.getCode().equalsIgnoreCase(changeType)){
        //储罐区
        if("删除".equals(changeOperation)){
        bpStorageTankAreaDao.deleteById(id);
        return;
        }
        changeStorageTankArea(id, fieldMap);
        }else if(ChangeRecordType.MANUFACT_TECH.getCode().equalsIgnoreCase(changeType)){
        //工艺流程
        if("删除".equals(changeOperation)){
        bpManufacturingTechDao.deleteById(id);
        return;
        }
        changManufactTech(id, fieldMap);
        }else if(ChangeRecordType.MONITOR_POINT.getCode().equalsIgnoreCase(changeType)){
        //监测点
        if("删除".equals(changeOperation)){
        mhMonitoringPointService.deleteById(id);
        return;
        }
        changMonitorPoint(id, fieldMap);
        }
        }


/**
 * 人员管理
 * @param id
 * @param fieldMap
 */
private void changeUser(Long id,  Map<String, Object> fieldMap) throws IllegalAccessException {
        Optional<BaseUser> optional = baseUserDao.findById(id);
        if(!optional.isPresent()){
        return;
        }
        BaseUser entity = optional.get();
        BeanWrapper bw = new BeanWrapperImpl(entity);
        //动态更新字段
        writeProperty(bw,fieldMap,ChangeRecordType.USER.getCode());
        baseUserDao.save(entity);
        }

private void writeProperty(BeanWrapper bw, Map<String, Object> fieldMap, String changeType){
        fieldMap.forEach((key, value)->{
        //储罐区： 风险分区
        if("mhMajorHazard".equalsIgnoreCase(key)){
        Optional<MhMajorHazard> mhMajorHazard = mhMajorHazardDao.findById(new Long(value.toString()));
        if(mhMajorHazard.isPresent()){
        bw.setPropertyValue(key, mhMajorHazard.get());
        }
        }else if ("image".equalsIgnoreCase(key)) {
        //图片需要特殊处理
        processImage(bw, key, value, changeType);
        }else if("workTemperatureRange".equalsIgnoreCase(key)) {
        if(value != null){
        JSONArray range = JSON.parseArray(value.toString());
        if(range.get(0) != null){
        bw.setPropertyValue("workTemperatureLowValue",range.get(0));
        }
        if(range.get(1) != null){
        bw.setPropertyValue("workTemperatureHighValue",range.get(1));
        }
        }

        }else if("workPressureHighRange".equalsIgnoreCase(key)) {
        if(value != null){
        JSONArray range = JSON.parseArray(value.toString());
        if(range.get(0) != null){
        bw.setPropertyValue("workPressureLowValue",range.get(0));
        }
        if(range.get(1) != null){
        bw.setPropertyValue("workPressureHighValue",range.get(1));
        }
        }
        }else if ("bpStorageTankArea".equalsIgnoreCase(key)) {
        bw.setPropertyValue("location",value==null ? "" : value.toString());
        }else{

        Class type = bw.getPropertyType(key);
        if (value != null && type.getName().equals("java.util.Date") || type.getName().equals("java.time.LocalDate")) {
        try {
        if (value.toString().length() == 10) {
        bw.setPropertyValue(key, DateTimeUtil.parseDate(value.toString()));
        } else {
        bw.setPropertyValue(key, DateTimeUtil.parseDateTime(value.toString()));
        }
        } catch (ParseException e) {
        log.error("执行变更 日期转换出错： " + value, e);
        }
        } else if (value != null && type.getName().equals("java.lang.Long")) {
        bw.setPropertyValue(key, new Long(value.toString()));
        } else if (value != null && type.getName().equals("java.lang.Integer")) {
        bw.setPropertyValue(key, new Integer(value.toString()));
        } else if (value != null && type.getName().equals("java.lang.Double")) {
        bw.setPropertyValue(key, new Double(value.toString()));
        } else if (value != null && type.getName().equals("java.lang.Float")) {
        bw.setPropertyValue(key, new Float(value.toString()));
        } else if (value != null && type.getName().equals("java.lang.Boolean")) {
        bw.setPropertyValue(key, new Boolean(value.toString()));
        } else if (value != null && type.getName().equals("java.lang.String")) {

        bw.setPropertyValue(key, value.toString());
        }else{
             bw.setPropertyValue(key, value);
        }
        }


        });
        }

private void processImage(BeanWrapper bw, String key, Object value, String changeType){
        if(value != null && StringUtils.isNotEmpty(value.toString())){
        JSONObject img = JSONObject.parseObject(value.toString());
        Long imageId = img.getLong("id");

        if(ChangeRecordType.USER.getCode().equalsIgnoreCase(changeType)){
        //人员证件照
        bw.setPropertyValue("idCardImgId", imageId);
        }else if(ChangeRecordType.MANUFACT_TECH.getCode().equalsIgnoreCase(changeType)){
        //工艺流程图
        bw.setPropertyValue("techProgressPicture", imageId);
        }else  if(ChangeRecordType.USER_CERTIFICATE.getCode().equalsIgnoreCase(changeType)){
        //人员资质证件 照片
        String downloadUrl = img.getString("downloadUrl");
        bw.setPropertyValue("imageId", imageId);
        bw.setPropertyValue("downloadurl", downloadUrl);
        }

        }
        }

// 人员资质证件
private void changeUserCertificate(Long id, Map<String, Object> fieldMap){
        Optional<BpCertificate> optional = bpCertificateDao.findById(id);
        if(!optional.isPresent()){
        return;
        }
        BpCertificate entity = optional.get();
        BeanWrapper bw = new BeanWrapperImpl(entity);
        //动态更新字段
        writeProperty(bw,fieldMap,ChangeRecordType.USER_CERTIFICATE.getCode());
        bpCertificateDao.save(entity);
        }

// 设备设施
private void changeDevice(Long id, Map<String, Object> fieldMap){
        Optional<BpProductionFacility> optional = bpProductionFacilityDao.findById(id);
        if(!optional.isPresent()){
        return;
        }
        BpProductionFacility entity = optional.get();
        BeanWrapper bw = new BeanWrapperImpl(entity);
        //动态更新字段
        writeProperty(bw,fieldMap,ChangeRecordType.DEVICE.getCode());
        bpProductionFacilityDao.save(entity);
        }

// 储罐
private void changeStorageTank(Long id, Map<String, Object> fieldMap){
        Optional<BpStorageTank> optional = bpStorageTankDao.findById(id);
        if(!optional.isPresent()){
        return;
        }
        BpStorageTank entity = optional.get();
        BeanWrapper bw = new BeanWrapperImpl(entity);
        //动态更新字段
        writeProperty(bw,fieldMap,ChangeRecordType.STORAGE_TANK.getCode());
        bpStorageTankDao.save(entity);
        }

//储罐区
private void changeStorageTankArea(Long id, Map<String, Object> fieldMap){
        Optional<BpStorageTankArea> optional = bpStorageTankAreaDao.findById(id);
        if(!optional.isPresent()){
        return;
        }
        BpStorageTankArea entity = optional.get();
        BeanWrapper bw = new BeanWrapperImpl(entity);
        //动态更新字段
        writeProperty(bw,fieldMap,ChangeRecordType.STORAGE_TANK_AREA.getCode());
        bpStorageTankAreaDao.save(entity);
        }

//工艺流程
private void changManufactTech(Long id, Map<String, Object> fieldMap){
        Optional<BpManufacturingTech> optional = bpManufacturingTechDao.findById(id);
        if(!optional.isPresent()){
        return;
        }
        BpManufacturingTech entity = optional.get();
        BeanWrapper bw = new BeanWrapperImpl(entity);
        //动态更新字段
        writeProperty(bw,fieldMap,ChangeRecordType.MANUFACT_TECH.getCode());
        bpManufacturingTechDao.save(entity);
        }

//监测点
private void changMonitorPoint(Long id, Map<String, Object> fieldMap){
        Optional<MhMonitoringPoint> optional = mhMonitoringPointDao.findById(id);
        if(!optional.isPresent()){
        return;
        }
        MhMonitoringPoint entity = optional.get();
        if(fieldMap.containsKey("name")){
        entity.setName(fieldMap.get("name").toString());
        }
        if(fieldMap.containsKey("pointCode")){
        entity.setPointCode(fieldMap.get("pointCode").toString() );
        }
        if(fieldMap.containsKey("monitoringTypeId")){
        Optional<MhMonitoringType> monitoringType = mhMonitoringTypeDao.findById(new Long(fieldMap.get("monitoringTypeId").toString()));
        if(monitoringType.isPresent()){
        entity.setMhMonitoringType(monitoringType.get());
        }
        }
        // 量程上限
        if(fieldMap.containsKey("highValue")){
        entity.setHighValue(fieldMap.get("highValue")== null || StringUtils.isEmpty(fieldMap.get("highValue").toString())
        ? null : fieldMap.get("highValue").toString());
        }
        // 量程下限
        if(fieldMap.containsKey("lowValue")){
        entity.setLowValue(fieldMap.get("lowValue")== null || StringUtils.isEmpty(fieldMap.get("lowValue").toString())
        ? null : fieldMap.get("lowValue").toString());
        }

        if(fieldMap.containsKey("level1Threshold")){
        entity.setLevel1Threshold(fieldMap.get("level1Threshold")== null || StringUtils.isEmpty(fieldMap.get("level1Threshold").toString())
        ? null : fieldMap.get("level1Threshold").toString());
        }
        if(fieldMap.containsKey("level2Threshold")){
        entity.setLevel2Threshold(fieldMap.get("level2Threshold")== null || StringUtils.isEmpty(fieldMap.get("level2Threshold").toString())
        ? null : fieldMap.get("level2Threshold").toString());
        }
        // 高报
        if(fieldMap.containsKey("highValue1")){
        entity.setHighValue1(fieldMap.get("highValue1")== null || StringUtils.isEmpty(fieldMap.get("highValue1").toString())
        ? null : fieldMap.get("highValue1").toString());
        }
        // 高高报
        if(fieldMap.containsKey("highValue2")){
        entity.setHighValue2(fieldMap.get("highValue2")== null || StringUtils.isEmpty(fieldMap.get("highValue2").toString())
        ? null : fieldMap.get("highValue2").toString());
        }
        //低报
        if(fieldMap.containsKey("lowValue1")){
        entity.setLowValue1(fieldMap.get("lowValue1")== null || StringUtils.isEmpty(fieldMap.get("lowValue1").toString())
        ? null :fieldMap.get("lowValue1").toString());
        }
        //低低报
        if(fieldMap.containsKey("lowValue2")){
        entity.setLowValue2(fieldMap.get("lowValue2")== null || StringUtils.isEmpty(fieldMap.get("lowValue2").toString())
        ? null : fieldMap.get("lowValue2").toString());
        }

        mhMonitoringPointService.edit(entity);

        }




        }
